/****************************************************************************/
/* File: scs-display.cpp                                                    */
/* Desc: Implementation file for the video display type                     */
/* Created: 2014-11-12                                                      */
/* Revised: 2014-11-14                                                      */
/* Authors: Sterling P. de Mille                                            */
/****************************************************************************/

// specification file
#include "scs-display.h"


SCSdisplay* SCSdisplay::m_pkSingleton = NULL;

SCSdisplay::SCSdisplay ()
{
	assert(!m_pkSingleton);
	m_pkSingleton = this;

	m_pkFrameBuffer = NULL;
	m_kClearColor = SCScolor(0);
}

SCSdisplay::~SCSdisplay ()
{
	m_pkFrameBuffer = NULL;
	m_kClearColor = SCScolor(0);
}

SCSerror SCSdisplay::Create (const SCSbool iFullscreen)
{
	IMG_Init(IMG_INIT_JPG | IMG_INIT_PNG | IMG_INIT_TIF);
	const SDL_VideoInfo* pkInfo = SDL_GetVideoInfo();
	SCSint32u iFlags = (SDL_OPENGL | SDL_DOUBLEBUF);
	SCSint aaiDisplays [][2] = {
		{ 1920, 1080 },
		{ 1366, 768 },
		{ 1360, 768 },
		{ 1280, 960 },
		{ 1280, 720 },
		{ 1024, 768 },
		{ 800, 600 },
		{ 720, 576 },
		{ 704, 576 },
		{ 720, 480 },
		{ 704, 480 },
		{ 640, 480 },
		{}
	};
	if (pkInfo->hw_available) {
		iFlags |= SDL_HWSURFACE;
	} else {
		iFlags |= SDL_SWSURFACE;
	}
	if (iFullscreen) {
		iFlags |= (SDL_FULLSCREEN | SDL_NOFRAME);
	}
	SDL_Rect** hkModes = SDL_ListModes(NULL, iFlags | SDL_FULLSCREEN);
	if (hkModes == (SDL_Rect**)(0))
		return (SCS_ERROR_VIDEO | SCS_ERROR_CREATE | SCS_ERROR_DISPLAY);
	if (hkModes == (SDL_Rect**)(-1)) {
		SCSint iSizeX = aaiDisplays[0][0];
		SCSint iSizeY = aaiDisplays[0][1];
		SCSint iBPP;
		if ((iBPP = SDL_VideoModeOK(iSizeX, iSizeY, 32, iFlags | SDL_FULLSCREEN)) != 0) {
			if(SDL_SetVideoMode(iSizeX, iSizeY, iBPP, iFlags) == NULL) {
				return (SCS_ERROR_VIDEO | SCS_ERROR_CREATE | SCS_ERROR_DISPLAY);
			}
			m_pkFrameBuffer = SDL_GetVideoSurface();
			return SCS_ERROR_NONE;
		}
	} else {
		for (SCSint iMode = 0; (aaiDisplays[iMode] != NULL); iMode++) {
			SCSint iSizeX = aaiDisplays[iMode][0];
			SCSint iSizeY = aaiDisplays[iMode][1];
			SCSint iBPP;
			if ((iBPP = SDL_VideoModeOK(iSizeX, iSizeY, 32, iFlags | SDL_FULLSCREEN)) != 0) {
				if(SDL_SetVideoMode(iSizeX, iSizeY, iBPP, iFlags) == NULL) {
					return (SCS_ERROR_VIDEO | SCS_ERROR_CREATE | SCS_ERROR_DISPLAY);
				}
				m_pkFrameBuffer = SDL_GetVideoSurface();
				return SCS_ERROR_NONE;
			}
		}
	}
	return (SCS_ERROR_VIDEO | SCS_ERROR_CREATE | SCS_ERROR_DISPLAY);
}

SCSerror SCSdisplay::Create (const SCSint iSizeX, const SCSint iSizeY, const SCSbool iFullscreen)
{
	const SDL_VideoInfo* pkInfo = SDL_GetVideoInfo();
	SCSint32u iFlags = (SDL_OPENGL | SDL_DOUBLEBUF);
	if (pkInfo->hw_available) {
		iFlags |= SDL_HWSURFACE;
	} else {
		iFlags |= SDL_SWSURFACE;
	}
	if (iFullscreen) {
		iFlags |= (SDL_FULLSCREEN | SDL_NOFRAME);
	}
	SCSint iBPP;
	if ((iBPP = SDL_VideoModeOK(iSizeX, iSizeY, 32, iFlags)) == 0)
		return (SCS_ERROR_VIDEO | SCS_ERROR_CREATE | SCS_ERROR_DISPLAY);
	if(SDL_SetVideoMode(iSizeX, iSizeY, iBPP, iFlags) == NULL) {
		return (SCS_ERROR_VIDEO | SCS_ERROR_CREATE | SCS_ERROR_DISPLAY);
	}
	m_pkFrameBuffer = SDL_GetVideoSurface();

	return SCS_ERROR_NONE;
}

SCSint SCSdisplay::SizeX () const
{
	return m_pkFrameBuffer->w;
}

SCSint SCSdisplay::SizeY () const
{
	return m_pkFrameBuffer->h;
}

SCSint SCSdisplay::BitDepth () const
{
	return m_pkFrameBuffer->format->BitsPerPixel;
}

SCSbool SCSdisplay::HardwareEnabled () const
{
	SCSbool iAvailable = SDL_GetVideoInfo()->hw_available;
	SCSbool iAssigned = ((m_pkFrameBuffer->flags & SDL_HWSURFACE) > 0);
	return (iAvailable && iAssigned);
}

SDL_Surface* SCSdisplay::FrameBuffer () const
{
	return m_pkFrameBuffer;
}

void SCSdisplay::Update ()
{
	SDL_GL_SwapBuffers();
}

void SCSdisplay::Clear ()
{
	SCSint8u iR, iG, iB, iA;
	iR = ((SCSint8u)((m_kClearColor.GetRed() * 0xff) + 0.5f) & 0xff);
	iG = ((SCSint8u)((m_kClearColor.GetGreen() * 0xff) + 0.5f) & 0xff);
	iB = ((SCSint8u)((m_kClearColor.GetBlue() * 0xff) + 0.5f) & 0xff);
	iA = ((SCSint8u)((m_kClearColor.GetAlpha() * 0xff) + 0.5f) & 0xff);
	SDL_FillRect(m_pkFrameBuffer, NULL, SDL_MapRGBA(m_pkFrameBuffer->format, iR, iG, iB, iA));
}

void SCSdisplay::SetClearColor (const SCSfloat fRed, const SCSfloat fGreen, const SCSfloat fBlue, const SCSfloat fAlpha)
{
	m_kClearColor.SetRGB(fRed, fGreen, fBlue, fAlpha);
}

void SCSdisplay::SetClearColor (const SCScolor& rkColor)
{
	m_kClearColor.SetColor(rkColor);
}

SCScolor SCSdisplay::GetClearColor () const
{
	return m_kClearColor;
}

SCSdisplay* SCSdisplay::Singleton ()
{
	return m_pkSingleton;
}
